package com.scs.application.modules.wm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.BeanUtils;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.modules.base.entity.Matr;
import com.scs.application.modules.base.entity.MatrUnit;
import com.scs.application.modules.base.service.MatrUnitService;
import com.scs.application.modules.base.util.CommonService;
import com.scs.application.modules.base.util.SingleService;
import com.scs.application.modules.wm.entity.Stock;
import com.scs.application.modules.wm.entity.WorkOrder;
import com.scs.application.modules.wm.entity.WorkOrderItem;
import com.scs.application.modules.wm.enums.LockBusType;
import com.scs.application.modules.wm.enums.UniqueCodeType;
import com.scs.application.modules.wm.mapper.WorkOrderItemMapper;
import com.scs.application.modules.wm.mapper.WorkOrderMapper;
import com.scs.application.modules.wm.service.OutOrderItemService;
import com.scs.application.modules.wm.service.StockLockService;
import com.scs.application.modules.wm.service.StockService;
import com.scs.application.modules.wm.service.WorkOrderService;
import com.scs.application.modules.wm.utils.ServiceState;
import com.scs.application.modules.wm.utils.UniqueCodeUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 入库单明细 服务实现类
 * </p>
 */
@Service
public class OutOrderItemServiceImpl extends BaseServiceImpl<WorkOrderItemMapper, WorkOrderItem> implements OutOrderItemService {

    @Autowired
    private WorkOrderService workOrderService;

    @Autowired
    private StockService stockService;

    @Autowired
    private StockLockService stockLockService;

    @Autowired
    private WorkOrderMapper workOrderMapper;

    @Autowired
    @Lazy
    private MatrUnitService matrUnitService;



    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdate(WorkOrderItem workOrderItem) {
        //数据库中是Long类型，不能存空值
        if (StringUtils.isBlank(workOrderItem.getLineId()))
            workOrderItem.setLineId(null);
        if (StringUtils.isBlank(workOrderItem.getStockId()))
            workOrderItem.setStockId(null);

        // 包装数量修改后
        if (workOrderItem.getPackageRate() * workOrderItem.getPackageQty() != workOrderItem.getSkuQty()) {
            workOrderItem.setSkuQty(workOrderItem.getPackageRate() * workOrderItem.getPackageQty());
            workOrderItem.setAmount(workOrderItem.getSkuQty() * workOrderItem.getSkuPrice());
            Stock stock = stockService.getStockByUC(workOrderItem.getSn());
            BusinessException.throwValidFailIf(
                    workOrderItem.getSkuQty() > stock.getSkuQty() ,
                    "退库数量%s已超过库存数量%s,请修改",
                    workOrderItem.getSkuQty(),
                    stock.getSkuQty()
            );
        }

        Boolean boolResult = super.saveOrUpdate(workOrderItem);
        if (boolResult) { //重刷一下订单总价
            workOrderService.calculateOrderPrice(workOrderItem.getWorkOrderId());
        }

        return boolResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeCascadeByIds(Collection<? extends Serializable> idList) {
        List<String> workOrderIds = this.listObjs(Wrappers.<WorkOrderItem>query()
                        .select("work_order_id").in("id", idList).groupBy("work_order_id"),
                v -> v.toString());
        //解锁
        List<String> stockIds = this.listObjs(Wrappers.<WorkOrderItem>query()
                .select("stock_id").in("id", idList), v-> v.toString());
        Boolean boolResult = this.removeByIds(idList);
        if (boolResult && workOrderIds.size() > 0) { //重刷一下订单总价
            workOrderService.calculateOrderPrice(workOrderIds.get(0));
        }
        if (boolResult && stockIds.size() > 0) { //解锁重刷一下订单总价
            stockIds.forEach(stockId -> stockLockService.unlock(stockId));
        }
        return boolResult;
    }

    //扫码入出库单
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized Map<String,Object> addByScan(String workOrderId, String uniqueCode) {
        Map<String,Object> result = new HashMap<String,Object>();

        // 如果扫描rfid此时rfid绑定多个SN所以要返回list
        List<String> sns = stockService.getStockListByUniqueCode(uniqueCode).stream().map(Stock::getSn).collect(Collectors.toList());

        if (UniqueCodeUtils.getUniqueCodeType(uniqueCode) == UniqueCodeType.RFID) {
            this.saveItmes(workOrderId, sns, uniqueCode);
        } else {
            this.saveItmes(workOrderId, sns, "");
        }
        return result;
    }

    //批量选择出库
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Map<String,Object> addBySelect(Map<String, Object> map) {
        Map<String,Object> result = new HashMap<String,Object>();
        //转list
        List<String> listSn = (List<String>) map.get("listSn");
        String workOrderId = (String) map.get("workOrderId");

        // 添加明细
        this.saveItmes(workOrderId, listSn, "");
        return result;
    }

    /**
     * 批量保存明细
     */
    private void saveItmes(String workOrderId, List<String> sns, String rfid) {
        WorkOrder workOrder = workOrderService.getById(workOrderId);
        if (workOrder == null) { BusinessException.throwValidFail("操作失败，对应出库单已被删除，id=%s",workOrderId); }
        if (CollectionUtils.isEmpty(sns)) { BusinessException.throwValidFail("请先扫描耗材"); }

        List<WorkOrderItem> selectedWorkOrderItems = super.list(new QueryWrapper<WorkOrderItem>().eq("work_order_id", workOrder.getId()).in("sn", sns));
        //选择的耗材已在明细中，批量删除明细
        if (selectedWorkOrderItems.size() > 0) {
            this.removeByIds(selectedWorkOrderItems.stream().map(WorkOrderItem::getId).collect(Collectors.toList()));
            //批量解除实物锁
            stockLockService.unlockBatch(sns);
        } else {
            // 加锁
            List<Stock> stocks = stockLockService.lockBatch(LockBusType.OUT_ORDER, workOrderId, workOrder.getWarehouseId(), "供应商出库锁库", sns,"OUT_SP");

            // 判断选择的供应商是否大于1
            List<Stock> distinctStockList = stocks.stream().filter(CommonService.distinctByKey(Stock::getSupplierId)).collect(Collectors.toList());
            if(distinctStockList.size() > 1){
                BusinessException.throwValidFail("只能选择一个供应商");
            }

            List<WorkOrderItem> workOrderItems = new ArrayList<>(stocks.size());
            String purchaseOrderType = workOrder.getPurchaseOrderType();

            if (stocks.isEmpty()) {
                BusinessException.throwValidFail(String.format("在库存中未找到%s相关的耗材", StringUtils.isEmpty(rfid) ? String.join(",", sns) : rfid));
            }

            boolean isBlank = StringUtils.isBlank(purchaseOrderType);
            List<Matr> matrs = SingleService.inst.matrService.list(Wrappers.<Matr>query().select("id,flag_omoc,flag_stock_reagent,base_type").in("id", stocks.stream().map(Stock::getMatrId).distinct().collect(Collectors.toList())).eq(!isBlank, "base_type", purchaseOrderType));
            if (isBlank) {
                purchaseOrderType = matrs.get(0).getBaseType();
                // 过滤不同耗材类型
                String orderType = purchaseOrderType;
                List<String> unlockSns = new ArrayList<>(stocks.size());
                int size = stocks.size();
                stocks = stocks.stream().filter(stock -> {
                    if (matrs.stream().anyMatch(matr -> matr.getId().equals(stock.getMatrId()) && matr.getBaseType().equals(orderType))) {
                        return true;
                    }
                    unlockSns.add(stock.getSn());
                    return false;
                }).collect(Collectors.toList());
                if (stocks.size() < size) {
                    // 批量解除实物锁
                    if (unlockSns.size() > 0) { stockLockService.unlockBatch(unlockSns); }
                    // 添加耗材过滤提示
                    ServiceState.set(ServiceState.VALID_MSG, String.format("批量添加成功，有%d个所选耗材属性与主单据不匹配，已忽略", size - stocks.size()));
                }
            } else if (matrs.isEmpty()) {
                BusinessException.throwValidFail("供应商退货单类型为[%s]，不可退货，请重新选择", GlobalConsts.MATR_BASE_TYPE_MAP.get(workOrder.getPurchaseOrderType()));
            }
            for (Stock stock : stocks) {
                if (!stock.getWarehouseId().equals(workOrder.getWarehouseId())) {
                    BusinessException.throwValidFail("主单据仓库跟所操作耗材不是同一个仓库");
                }
                if (!stock.getSupplierId().equals(workOrder.getSupplierId())) {
                    BusinessException.throwValidFail("主单据供应商跟所操作耗材不是一个供应商");
                }
                if (!stock.getFlagConsignment().equals(workOrder.getFlagConsignment())) {
                    BusinessException.throwValidFail("主单据寄售类型跟所操作耗材不一样");
                }
                if (!stock.getFlagOmoc().equals(workOrder.getFlagOmoc())) {
                    BusinessException.throwValidFail("主单据一物一码类型跟所操作耗材不一样");
                }
                WorkOrderItem workOrderItem = new WorkOrderItem();
                BeanUtils.copyProperties(stock, workOrderItem, "id");
                workOrderItem.setStockId(stock.getId()).setWorkOrderId(workOrder.getId());

                workOrderItem.setPackageRate(matrUnitService.getPackageRateByMatrIdAndUnitName(workOrderItem.getMatrId(),workOrderItem.getPackageUnit()));
                workOrderItems.add(workOrderItem);
            }
            if (workOrderItems.size() > 0) {
                super.saveBatch(workOrderItems);
                // 更新主单类型
                String orderType = purchaseOrderType;
                stocks.stream().filter(stock -> workOrderItems.stream().anyMatch(item -> stock.getId().equals(item.getStockId()))).findFirst().ifPresent(stock -> {
                    WorkOrder update = (WorkOrder) new WorkOrder().setPurchaseOrderType(orderType).setId(workOrder.getId());
                    workOrderMapper.updateById(update);
                });
            }
        }
        // 更新主单金额
        workOrderService.calculateOrderPrice(workOrder.getId());
    }

}
